﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; 
using System.Linq.Expressions;

namespace NMoq.Core
{
    public class MockHelper
    {
        #region store ,get or set Mock
        private static Dictionary<Type, Object> MockObjectDict = new Dictionary<Type, Object>();

        public static Mock<T> GetMock<T>()
        {
            Mock<T> mock = null;
            if (MockObjectDict.ContainsKey(typeof(T)))
            {
                mock = MockObjectDict[typeof(T)] as Mock<T>;
            }
            else
            {
                mock = new Mock<T>();
                MockObjectDict[typeof(T)] = mock;
            }
            return mock;
        }

        public static Mock<T> SetMock<T>(InterceptorActionAfterRead actionAfterRead)
        {
            Mock<T> mock = GetMock<T>();
            mock.SetupActionAfterRead(actionAfterRead);
            return mock;
        }

        public static void SetMock<T>(Mock<T> mock)
        {
            if (!MockObjectDict.ContainsKey(typeof(T)))
                MockObjectDict.Add(typeof(T), mock);
            else
                MockObjectDict[typeof(T)] = mock;
        }

        #endregion

        #region mock Action methods
        public static void MockActionMethod<T>(Expression<Action<T>> expression)
        {
            GetMock<T>().MockActionMethod(expression);
        }

        public static void MockActionMethod<T, TAction>(Expression<Action<T>> expression, TAction actionTarget)
            where TAction : IAction
        {
            GetMock<T>().MockActionMethod<TAction>(expression, actionTarget);
        }

        public static void MockActionMethod<T, TAction>(Expression<Action<T>> expression, Func<MethodMessageInfo, IEnumerable<TAction>, TAction> selectFunc)
            where TAction : IAction
        {
            GetMock<T>().MockActionMethod<TAction>(expression, selectFunc);
        }

        public static void MockActionMethod<T, TAction>(Expression<Action<T>> expression, Action<MethodMessageInfo, TAction> action)
            where TAction : IAction
        {
            GetMock<T>().MockActionMethod<TAction>(expression, action);
        }
        #endregion

        #region mock Func methods
        public static void MockFuncMethod<T, TResult>(Expression<Func<T, TResult>> expression)
        {
            GetMock<T>().MockFuncMethod<TResult>(expression);           
        }

        public static void MockFuncMethod<T, TResult, TAction>(Expression<Func<T, TResult>> expression, TAction actionTarget)
            where TAction:IAction 
        {
            GetMock<T>().MockFuncMethod<TResult, TAction>(expression, actionTarget);  
        }

        public static void MockFuncMethod<T, TResult, TAction>(Expression<Func<T, TResult>> expression, Action<MethodMessageInfo, TAction> action) 
            where TAction:IAction
        {
            GetMock<T>().MockFuncMethod<TResult, TAction>(expression, action);  
        }

        public static void MockFuncMethod<T, TResult, TAction>(Expression<Func<T, TResult>> expression, Func<MethodMessageInfo, IEnumerable<TAction>, TAction> selectFunc)
            where TAction : IAction
        {
            GetMock<T>().MockFuncMethod<TResult, TAction>(expression, selectFunc);  
        }
        #endregion

        #region call selector methods
        public static  void CallSelector<T>(Expression<Action<Selector<T>>> expression) where T : IAction
        {
            GetMock<T>().CallSelector<T>(expression);
        }

        public static  TResult CallSelector<T, TResult>(Expression<Func<Selector<T>, TResult>> expression) where T : IAction
        {
            return GetMock<T>().CallSelector<T, TResult>(expression);
        }
        #endregion

        #region mock all method of the class instance
        public static  void MockClass<T>()
        {
            GetMock<T>().MockClass();
        }

        public static void MockClass<T,TAction>(TAction actionTarget)
            where TAction : IAction
        {
            GetMock<T>().MockClass<TAction>(actionTarget);
        }
        #endregion

    }
}
